/* SPDX-License-Identifier: GPL-2.0-or-later */
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * heartbeat.h
 *
 * Function prototypes
 *
 * Copyright (C) 2004 Oracle.  All rights reserved.
 */

#ifndef O2CLUSTER_HEARTBEAT_H
#define O2CLUSTER_HEARTBEAT_H
#include <linux/blkdev.h>

#include "ocfs2_heartbeat.h"
#include "ocfs2_nodemanager.h"

#define O2HB_REGION_TIMEOUT_MS		2000

#define O2HB_MAX_REGION_NAME_LEN	32
/* be consistent with osb uuid_str (OCFS2_VOL_UUID_LEN * 2) */
#define O2HB_REGION_UUID_LEN		32

/* number of changes to be seen as live */
#define O2HB_LIVE_THRESHOLD	   3
/* Otherwise MAX_WRITE_TIMEOUT will be zero... */
#define O2HB_MIN_DEAD_THRESHOLD	  2

#define O2HB_CB_MAGIC		0x51d1e4ec

#define O2HB_DEFAULT_FAKE_DEAD_THRESHOLD 61
#define O2HB_DEFAULT_REAL_DEAD_THRESHOLD 61

extern unsigned int o2hb_fake_dead_threshold;
extern unsigned int o2hb_real_dead_threshold;

#define O2HB_WRITE_FAKE_TIMEOUT_MS (O2HB_REGION_TIMEOUT_MS * \
		(o2hb_fake_dead_threshold - 1))
#define O2HB_WRITE_REAL_TIMEOUT_MS (O2HB_REGION_TIMEOUT_MS * \
		(o2hb_real_dead_threshold - 1))

/* node state to be displayed in debugfs */
#define NODE_STATE_UMOUNT 0
#define NODE_STATE_MOUNTED 1
#define NODE_STATE_FAKETIMEOUT 2
#define NODE_STATE_CONNERR 3
#define NODE_STATE_QUORUM 4
#define NODE_STATE_FENCE 5
#define NODE_STATE_QUORUM_DELAY_2S 6  /* used to delay display state QUORUM */

/* callback stuff */
enum o2hb_callback_type {
	O2HB_NODE_DOWN_CB = 0,
	O2HB_NODE_UP_CB,
	O2HB_REGION_DOWN_CB,
	O2HB_REGION_UP_CB,
	O2HB_DISK_TIMEOUT_CB,
	O2HB_COMPLETE_LOCKRES_CB,
	O2HB_FENCE_SCSI_CB,
	O2HB_NUM_CB,
};

struct o2hb_query_join {
	__be16 node_num;
	__be16 pad1;
	__be32 pad2;
	__be64 genaration;
	u8 uuid_name[O2NM_MAX_NAME_LEN];
};

struct o2hb_conn_query {
	__be16 node_idx;
	__be16 err_node;
	__be32 pad2;
};

#define O2HB_MOD_KEY (0x666c6170)
enum {
	O2HB_CONN_FAILURE_QUERY = 101,
};

struct o2nm_node;
typedef void (o2hb_cb_func)(struct o2nm_node *, int, void *, u64);

struct o2hb_callback_func {
	u32			hc_magic;
	struct list_head	hc_item;
	o2hb_cb_func		*hc_func;
	void			*hc_data;
	int			hc_priority;
	enum o2hb_callback_type hc_type;
	char region_uuid[O2HB_REGION_UUID_LEN + 1];
};

struct o2hb_io_wait_ctxt {
	atomic_t          wc_num_reqs;
	struct completion wc_io_complete;
	int               wc_error;
};

struct config_group *o2hb_alloc_hb_set(void);
void o2hb_free_hb_set(struct config_group *group);

void o2hb_setup_callback(struct o2hb_callback_func *hc,
			 enum o2hb_callback_type type,
			 o2hb_cb_func *func,
			 void *data,
			 int priority,
			 const char *uuid);
int o2hb_register_callback(const char *region_uuid,
			   struct o2hb_callback_func *hc);
void o2hb_unregister_callback(const char *region_uuid,
			      struct o2hb_callback_func *hc);
void o2hb_fill_node_map(unsigned long *map,
			unsigned int bytes, const char *uuid);
void o2hb_fill_node_map_and_generation(unsigned long *map, unsigned int bytes,
		u32 *HBGen[], const char *uuid);
int o2hb_get_livenode_nr(const char *uuid);
void o2hb_exit(void);
int o2hb_init(void);

void o2hb_conn_state_change(u16 nd_num, u8 nd_state);

int o2hb_check_node_heartbeating_from_callback(u16 node_num, const char *uuid);
void o2hb_stop_all_regions(void);
int o2hb_get_all_regions(char *region_uuids, u8 numregions);
int o2hb_global_heartbeat_active(void);
void o2hb_quorum_region(void);
void o2hb_clear_domain_map(const char *domain_name, u16 node_num);
void o2hb_set_domain_map(const char *domain_name, u16 node_num);
int o2hb_test_domain_map_by_key(u16 node_num, u32 key);
void o2hb_handle_invalid(const char *domain_name);
void o2hb_disk_timeout(char *uuid);
int o2hb_disable_fence(void);
int o2hb_check_if_quorum(void);
int o2hb_is_unclean_stop(const char *uuid);

void o2hb_clear_fence_state(const char *region_uuid);
struct block_device *o2hb_get_block_device(const char *domain_name);
int o2hb_check_heartbeating_type(const char *domain_name);
bool o2hb_conn_normal(const char *domain_name);
bool o2hb_is_in_domain(const char *domain_name, u16 node_num);

void o2hb_end_req(struct request *rq, blk_status_t error);
int o2hb_execute_req(struct block_device *bdev, int rw,
		char *buf, unsigned int buf_len, unsigned char *cmd,
		struct o2hb_io_wait_ctxt *rb, int nowait);
void o2hb_free_device_list(struct list_head *dev_list);
int o2hb_get_dev_segment(struct block_device *bdev,
		struct list_head *dev_list);
void o2hb_fence_scsi(struct block_device *bdev, int node_num);
int o2hb_dlm_existed(u16 node_num);

int o2hb_inconsistent_nodes_info_output(char *buf, int buf_len);

#endif /* O2CLUSTER_HEARTBEAT_H */
